using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Reflection;

namespace ProfileTableDqEstimator
{
    internal class ProfileTableDqEstimatorAlgExecuter : IProfileTableDqEstimatorAlgExecuter
    {
        public string ExecuteAlgorithm(ProfTableQuery profTblQuery, IList<string> header, IEnumerable<string[]> data)
        {
            //Filter the results, select the most selective
            //We assume there is a grouping ID at the first column
            Debug.Assert(data != null, "table != null");
            if (!header[0].Equals("grp_id", StringComparison.InvariantCultureIgnoreCase))
                throw new DataException("First columns of the data is expected to be the grouping ID.");
            var headerDic = header
                .Select((v, i) => new {v, i})
                .Skip(1)
                .TakeWhile(v => !v.v.Contains(".")) //Just select columns upto metric cols
                .ToDictionary(v => v.v, v => v.i);
            var result = data.Where(r => QueryMatches(profTblQuery, r, headerDic)).Select(r => r)
                .OrderBy(r => r[0])
                .FirstOrDefault();
            return result != null ? string.Join(",", result) : null;
        }

        private static bool QueryMatches(ProfTableQuery profTblQuery, string[] strings, Dictionary<string, int> headerDic)
        {
            Func<Tuple<string, string>, bool> tupleIsInData = 
            t => t.Item2.Equals(strings[headerDic[t.Item1]], StringComparison.InvariantCultureIgnoreCase) ||
                 string.IsNullOrWhiteSpace(strings[headerDic[t.Item1]]);
            profTblQuery.EqualityConditions
                .Where(c => !headerDic.ContainsKey(c.Item1))
                .ToList()
                .ForEach(s => { throw new InvalidFilterCriteriaException( string.Format("Field '{0}' in the query does not exist in data.", s.Item1)); });
            return profTblQuery.EqualityConditions
                .All(tupleIsInData);
        }
    }
}